package com.fast.alden.admin.aspect;

import com.fast.alden.admin.service.SysLoginLogService;
import com.fast.alden.admin.util.SecurityUtils;
import com.fast.alden.common.entity.dto.LoginParam;
import com.fast.alden.common.entity.dto.LoginResult;
import com.fast.alden.common.service.TokenService;
import com.fast.alden.common.util.IpUtils;
import com.fast.alden.data.model.SysLoginLog;
import com.fast.alden.data.model.SysLoginType;
import com.fast.alden.data.model.SysUser;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

/**
 * 登录注销操作日志切面
 */
@Aspect
@Component
@Slf4j
public class RecordLoginLog {
    @Resource
    private SysLoginLogService loginLogService;
    @Resource
    private TokenService tokenService;

    /**
     * 定义切入点
     */
    @Pointcut("execution(* com.fast.alden.admin.service.AuthService.login(..))")
    public void performLogin() {

    }

    @Pointcut("execution(* com.fast.alden.admin.service.AuthService.logout(..))")
    public void performLogout() {

    }

    @Pointcut("execution(* com.fast.alden.admin.service.SysOnlineUserService.forceLogout(..))")
    public void performForceLogout() {

    }

    /**
     * 记录登录日志
     */
    @Around("performLogin()")
    public Object recordLoginLog(ProceedingJoinPoint joinPoint) throws Throwable {
        LoginParam loginParam = (LoginParam) joinPoint.getArgs()[0];

        SysLoginLog loginLog = new SysLoginLog();
        loginLog.setType(SysLoginType.LOGIN);
        loginLog.setOperationTime(LocalDateTime.now());
        loginLog.setIp(IpUtils.getIpAddr());
        loginLog.setUsername(loginParam.getUsername());

        try {
            LoginResult ret = (LoginResult) joinPoint.proceed();
            loginLog.setSuccess(true);
            log.info(String.format("%s登录成功", loginLog.getUsername()));
            return ret;
        } catch (Throwable throwable) {
            loginLog.setSuccess(false);
            loginLog.setMessage(throwable.getMessage());
            log.error(String.format("%s登录失败", loginLog.getUsername()));
            throw throwable;
        } finally {
            saveLog(loginLog);
        }
    }

    /**
     * 记录登录日志
     */
    @Around("performLogout()")
    public Object recordLogoutLog(ProceedingJoinPoint joinPoint) throws Throwable {
        SysUser user = SecurityUtils.getCurrentUser();

        SysLoginLog loginLog = new SysLoginLog();
        loginLog.setType(SysLoginType.LOGOUT);
        loginLog.setOperationTime(LocalDateTime.now());
        loginLog.setIp(IpUtils.getIpAddr());
        loginLog.setUsername(user.getUsername());

        try {
            LoginResult ret = (LoginResult) joinPoint.proceed();
            loginLog.setSuccess(true);
            log.info(String.format("%s退出成功", loginLog.getUsername()));
            return ret;
        } catch (Throwable throwable) {
            loginLog.setSuccess(false);
            loginLog.setMessage(throwable.getMessage());
            log.error(String.format("%s退出失败", loginLog.getUsername()));
            throw throwable;
        } finally {
            saveLog(loginLog);
        }
    }

    /**
     * 记录登录日志
     */
    @Around("performForceLogout()")
    public Object recordForceLogoutLog(ProceedingJoinPoint joinPoint) throws Throwable {
        String token = (String) joinPoint.getArgs()[0];
        String username = tokenService.getUserNameFromToken(token);

        SysLoginLog loginLog = new SysLoginLog();
        loginLog.setType(SysLoginType.FORCE_LOGOUT);
        loginLog.setOperationTime(LocalDateTime.now());
        loginLog.setIp(IpUtils.getIpAddr());
        loginLog.setUsername(username);

        try {
            LoginResult ret = (LoginResult) joinPoint.proceed();
            loginLog.setSuccess(true);
            log.info(String.format("%s强制退出成功", loginLog.getUsername()));
            return ret;
        } catch (Throwable throwable) {
            loginLog.setSuccess(false);
            loginLog.setMessage(throwable.getMessage());
            log.error(String.format("%s强制退出失败", loginLog.getUsername()));
            throw throwable;
        } finally {
            saveLog(loginLog);
        }
    }

    public void saveLog(SysLoginLog loginLog) {
        // 使用虚拟线程保存，跳出原方法的事务管理，如需使用操作系统线程请改为调用ThreadPoolTaskExecutor.execute方法
        Thread.ofVirtual().start(() -> {
            loginLogService.create(loginLog);
        });
    }
}
